package application.anno.impl;

import application.anno.FXService;
import application.backstage.BackStageService;
import application.constant.Constant;
import application.manager.InjectionManager;
import application.manager.ServiceManager;
import application.manager.annotationManager.AutoCloseManager;
import application.util.ReflectionsUtil;
import javafx.concurrent.Service;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Set;

public class FXServiceImpl {

    public void startService() {
        Set<Class<?>> serviceClass = ReflectionsUtil.getAnnotationByClass(FXService.class);
        for (Class<?> cls : serviceClass) {
            FXService FXService = cls.getAnnotation(FXService.class);
            if (Constant.ServiceParam.START_TIME.equals(FXService.runTime())) {
                Object object = getObject(cls);
                BackStageService<Object> objectBackStageService = runService(FXService, object);
                InjectionManager.getInstance().register(cls, object);
                ServiceManager.getInstance().register((Class<? extends Service<?>>) cls, objectBackStageService);
            } else if (!FXService.runnableMethod().isEmpty()) {
                Object object = getObject(cls);
                BackStageService<Object> objectBackStageService = runService(FXService.runnableMethod(), object);
                registerStop(FXService.stopMethod(), object);
                InjectionManager.getInstance().register(cls, object);
                ServiceManager.getInstance().register((Class<? extends Service<?>>) cls, objectBackStageService);
            }
        }
    }

    private void registerStop(String stopMethod, Object object) {
        Class<?> aClass = object.getClass();
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            if (method.getName().endsWith(stopMethod)) {
                AutoCloseManager.getInstance().getAutoCloses().put(object.getClass(), method);
                break;
            }
        }
    }

    public void close() throws InvocationTargetException, IllegalAccessException {
        Set<Class<?>> serviceAnnotation = ReflectionsUtil.getAnnotationByClass(FXService.class);
        for (Class<?> sClass : serviceAnnotation) {
            Method method = (Method) AutoCloseManager.getInstance().getAutoCloses().get(sClass);
            Object obj = InjectionManager.getInstance().lookup(sClass);
            if (method != null) {
                method.setAccessible(true);
                method.invoke(obj);
            }
            BackStageService<?> lookup = (BackStageService<?>) ServiceManager.getInstance().lookup(sClass);
            lookup.cancel();
        }
        ServiceManager.getInstance().stopAll();
    }

    private <T> BackStageService<T> runService(FXService FXService, T t) {
        Class<?> aClass = t.getClass();
        Method[] declaredMethods = aClass.getDeclaredMethods();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                Method init = null;
                Method startMethod = null;
                if (!FXService.initMethod().isEmpty()) {
                    for (Method method : declaredMethods) {
                        if (method.getName().endsWith(FXService.initMethod())) {
                            init = method;
                        } else if (method.getName().endsWith(FXService.startMethod())) {
                            startMethod = method;
                        } else if (method.getName().endsWith(FXService.stopMethod())) {
                            AutoCloseManager.getInstance().getAutoCloses().put(t.getClass(), method);
                        }
                    }
                }
                try {
                    if (init != null) {
                        init.setAccessible(true);
                        init.invoke(t);
                    }
                    if (startMethod != null) {
                        startMethod.setAccessible(true);
                        startMethod.invoke(t);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        };
        BackStageService<Runnable> backStageService = new BackStageService<Runnable>() {
            @Override
            protected void succeeded() {
                super.succeeded();
                // 注册各种监听事件
                for (Method method : declaredMethods) {
                    FXService annotation = t.getClass().getAnnotation(FXService.class);
                    if (annotation == null) {
                        continue;
                    }
                    if (!annotation.successCall().isEmpty()) {
                        if (method.getName().endsWith(annotation.successCall())) {
                            method.setAccessible(true);
                            try {
                                method.invoke(t);
                                break;
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                                break;
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                                break;
                            }
                        }
                    }
                }
            }

            @Override
            protected void failed() {
                super.failed();
                // 注册各种监听事件
                for (Method method : declaredMethods) {
                    FXService annotation = t.getClass().getAnnotation(FXService.class);
                    if (annotation == null) {
                        continue;
                    }
                    if (!annotation.failedCall().isEmpty()) {
                        if (method.getName().endsWith(annotation.failedCall())) {
                            method.setAccessible(true);
                            try {
                                method.invoke(t);
                                break;
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                                break;
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                                break;
                            }
                        }
                    }
                }
            }

            @Override
            protected void scheduled() {
                super.scheduled();
                // 注册各种监听事件
                for (Method method : declaredMethods) {
                    FXService annotation = t.getClass().getAnnotation(FXService.class);
                    if (annotation == null) {
                        continue;
                    }
                    if (!annotation.cancelCall().isEmpty()) {
                        if (method.getName().endsWith(annotation.cancelCall())) {
                            method.setAccessible(true);
                            try {
                                method.invoke(t);
                                break;
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                                break;
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                                break;
                            }
                        }
                    }
                }
            }
        };
        backStageService.init(runnable);
        backStageService.start();
        return (BackStageService<T>) backStageService;
    }

    private <T> BackStageService<T> runService(String methodName, T t) {
        Method startMethod = null;
        Method[] declaredMethods = t.getClass().getDeclaredMethods();
        for (Method method : declaredMethods) {
            if (method.getName().endsWith(methodName)) {
                startMethod = method;
                break;
            }
        }
        if (startMethod != null) {
            Method finalStartMethod = startMethod;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    finalStartMethod.setAccessible(true);
                    try {
                        finalStartMethod.invoke(t);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            };
            BackStageService<Runnable> backStageService = new BackStageService<Runnable>() {
                @Override
                protected void succeeded() {
                    super.succeeded();
                    // 注册各种监听事件
                    for (Method method : declaredMethods) {
                        FXService annotation = t.getClass().getAnnotation(FXService.class);
                        if (annotation == null) {
                            continue;
                        }
                        if (!annotation.successCall().isEmpty()) {
                            if (method.getName().endsWith(annotation.successCall())) {
                                method.setAccessible(true);
                                try {
                                    method.invoke(t);
                                    break;
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                    break;
                                } catch (InvocationTargetException e) {
                                    e.printStackTrace();
                                    break;
                                }
                            }
                        }
                    }
                }

                @Override
                protected void failed() {
                    super.failed();
                    // 注册各种监听事件
                    for (Method method : declaredMethods) {
                        FXService annotation = t.getClass().getAnnotation(FXService.class);
                        if (annotation == null) {
                            continue;
                        }
                        if (!annotation.failedCall().isEmpty()) {
                            if (method.getName().endsWith(annotation.failedCall())) {
                                method.setAccessible(true);
                                try {
                                    method.invoke(t);
                                    break;
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                    break;
                                } catch (InvocationTargetException e) {
                                    e.printStackTrace();
                                    break;
                                }
                            }
                        }
                    }
                }

                @Override
                protected void scheduled() {
                    super.scheduled();
                    // 注册各种监听事件
                    for (Method method : declaredMethods) {
                        FXService annotation = t.getClass().getAnnotation(FXService.class);
                        if (annotation == null) {
                            continue;
                        }
                        if (!annotation.cancelCall().isEmpty()) {
                            if (method.getName().endsWith(annotation.cancelCall())) {
                                method.setAccessible(true);
                                try {
                                    method.invoke(t);
                                    break;
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                    break;
                                } catch (InvocationTargetException e) {
                                    e.printStackTrace();
                                    break;
                                }
                            }
                        }
                    }
                }
            };
            backStageService.init(runnable);
            backStageService.start();
            return (BackStageService<T>) backStageService;
        }
        return null;
    }

    private <T> T getObject(Class<T> cls) {
        Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();
        for (Constructor<?> constructor : declaredConstructors) {
            if (constructor.getParameterCount() == 0) {
                if (constructor.getModifiers() == Modifier.PRIVATE) {
                    return null;
                } else {
                    constructor.setAccessible(true);
                    try {
                        return (T) constructor.newInstance();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return null;
    }
}
